package admin.server.service.impl;

import admin.server.service.UmsMenuService;
import admin.server.service.UmsResourceService;
import admin.dao.model.*;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import admin.common.vo.PageVo;
import admin.dao.mapper.UmsMenuMapper;
import admin.dao.mapper.UmsResourceMapper;
import admin.dao.mapper.UmsRoleMapper;
import admin.dao.mapper.UmsRoleMenuRelationMapper;
import admin.server.model.dto.UmsMenuNodeDto;
import admin.server.model.dto.UmsResourceDto;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 后台菜单管理Service实现类
 * Created by zgb on 2020/2/2.
 */
@Service
public class UmsMenuServiceImpl implements UmsMenuService {
    @Autowired
    private UmsMenuMapper menuMapper;
    @Autowired
    private UmsRoleMapper roleMapper;
    @Autowired
    private UmsResourceMapper resourceMapper;

    @Autowired
    private UmsRoleMenuRelationMapper roleMenuRelationMapper;

    @Autowired
    private UmsResourceService resourceService;



    public void uniqueCheck(UmsMenu record) throws Exception {
        if (StringUtils.isBlank(record.getName() )) {
            throw new Exception("名称 必填！");
        }
        //更新，不变
        if (record.getId() != null) {
            UmsMenu one = menuMapper.selectByPrimaryKey(record.getId());
            if (Objects.equals(one.getName(), record.getName()) ) {
                return;
            }
        }
        UmsMenuExample umsMenuExample = new UmsMenuExample();
        umsMenuExample.createCriteria().andNameEqualTo(record.getName());
        List<UmsMenu> list = menuMapper.selectByExample(umsMenuExample);
        if (!list.isEmpty()) {
            throw new Exception("名称 已存在 请勿重复添加！");
        }

    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(UmsMenu umsMenu) throws Exception {
        uniqueCheck(umsMenu);
        umsMenu.setCreateTime(new Date());
        updateLevel(umsMenu);
        menuMapper.insertSelective(umsMenu);
        List<Long> umsRoleIds =new ArrayList<>();
        UmsRoleExample umsRoleExample = new UmsRoleExample();
        if(!BooleanUtil.isTrue(umsMenu.getNecessaryYn())){
            umsRoleExample.createCriteria().andSupAdminYnEqualTo(true);
        }
        List<UmsRole> umsRoles = roleMapper.selectByExample(umsRoleExample);
        umsRoleIds.addAll(umsRoles.stream().map(e->e.getId()).collect(Collectors.toList()));
        for (Long umsRoleId : umsRoleIds) {
            UmsRoleMenuRelation umsRoleMenuRelation = new UmsRoleMenuRelation();
            umsRoleMenuRelation.setRoleId(umsRoleId);
            umsRoleMenuRelation.setMenuId(umsMenu.getId());
            roleMenuRelationMapper.insert(umsRoleMenuRelation);
        }
    }

    /**
     * 修改菜单层级
     */
    private void updateLevel(UmsMenu umsMenu) {
        if (umsMenu.getParentId() == 0) {
            //没有父菜单时为一级菜单
            umsMenu.setLevel(0);
        } else {
            //有父菜单时选择根据父菜单level设置
            UmsMenu parentMenu = menuMapper.selectByPrimaryKey(umsMenu.getParentId());
            if (parentMenu != null) {
                umsMenu.setLevel(parentMenu.getLevel() + 1);
            } else {
                umsMenu.setLevel(0);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(Long id, UmsMenu umsMenu) throws Exception {
        uniqueCheck(umsMenu);
        umsMenu.setId(id);
        updateLevel(umsMenu);
        return menuMapper.updateByPrimaryKeySelective(umsMenu);
    }

    @Override
    public UmsMenu getItem(Long id) {
        return menuMapper.selectByPrimaryKey(id);
    }


    private void loopDelete(Long id) {
        menuMapper.deleteByPrimaryKey(id);
        UmsRoleMenuRelationExample umsRoleMenuRelationExample = new UmsRoleMenuRelationExample();
        umsRoleMenuRelationExample.createCriteria().andMenuIdEqualTo(id);
        roleMenuRelationMapper.deleteByExample(umsRoleMenuRelationExample);
        UmsMenuExample umsMenuExample = new UmsMenuExample();
        umsMenuExample.createCriteria().andParentIdEqualTo(id);
        List<UmsMenu> umsMenus = menuMapper.selectByExample(umsMenuExample);
        if(!umsMenus.isEmpty()){
            for (UmsMenu umsMenu : umsMenus) {
                loopDelete(umsMenu.getId());
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        loopDelete(id);
        resourceService.initResourceRolesMap();
    }

    @Override
    public PageVo<UmsMenu> list(Long parentId, Integer pageSize, Integer pageNum) {
        PageHelper.startPage(pageNum, pageSize);
        UmsMenuExample example = new UmsMenuExample();
        example.setOrderByClause("sort desc");
        example.createCriteria().andParentIdEqualTo(parentId);
        List<UmsMenu> umsMenus = menuMapper.selectByExample(example);
        return PageVo.restPage(umsMenus,umsMenus);
    }



    @Override
    public List<UmsMenu> list(Integer level) {
        UmsMenuExample example = new UmsMenuExample();
        if(level!=null){
            example.createCriteria().andLevelEqualTo(level);
        }
        return menuMapper.selectByExample(example);
    }



    @Override
    public List<UmsMenuNodeDto> treeList(Boolean withResourceYn) {
        List<UmsMenu> menuList = menuMapper.selectByExample(new UmsMenuExample());
        List<UmsMenuNodeDto> result = menuList.stream()
                .filter(menu -> menu.getParentId().equals(0L))
                .map(menu -> covertMenuNode(menu, menuList, withResourceYn)).collect(Collectors.toList());
        return result;
    }


    @Override
    public int updateHidden(Long id, Boolean hidden) {
        UmsMenu umsMenu = new UmsMenu();
        umsMenu.setId(id);
        umsMenu.setHidden(hidden);
        return menuMapper.updateByPrimaryKeySelective(umsMenu);
    }

    @Override
    public List<UmsMenu> leafList( ){
        List<UmsMenu> result = new ArrayList<>();
        List<UmsMenuNodeDto> tree = this.treeList(false);
        for (UmsMenuNodeDto umsMenuNodeDto : tree) {
            result.addAll(tree2leaf(umsMenuNodeDto).stream().map(e->BeanUtil.toBean(e,UmsMenu.class)).collect(Collectors.toList()));
        }
        return result;
    }

    @Override
    public List<UmsMenu> noLeafList( ){
        List<UmsMenu> result = new ArrayList<>();
        List<UmsMenuNodeDto> tree = this.treeList(false);
        for (UmsMenuNodeDto umsMenuNodeDto : tree) {
            result.addAll(tree2NoLeaf(umsMenuNodeDto).stream().map(e->BeanUtil.toBean(e,UmsMenu.class)).collect(Collectors.toList()));
        }
        return result;
    }





    private List<UmsMenuNodeDto> tree2NoLeaf(UmsMenuNodeDto treeNodeBo) {
        List<UmsMenuNodeDto> list = new ArrayList<>();
        if (treeNodeBo == null) {
            return list;
        }
        if(!treeNodeBo.getChildren().isEmpty()){
            list.add(treeNodeBo);
            for (UmsMenuNodeDto child :treeNodeBo.getChildren() ) {
                list.addAll(tree2NoLeaf(child));
            }
        }
        return list;

    }




    private List<UmsMenuNodeDto> tree2leaf(UmsMenuNodeDto treeNodeBo) {
        List<UmsMenuNodeDto> list = new ArrayList<>();
        if (treeNodeBo == null) {
            return list;
        }
        if(treeNodeBo.getChildren().isEmpty()){
            list.add(treeNodeBo);
        }else{
            for (UmsMenuNodeDto child :treeNodeBo.getChildren() ) {
                list.addAll(tree2leaf(child));
            }
        }
        return list;

    }




    /**
     * 将UmsMenu转化为UmsMenuNode并设置children属性
     */
    private UmsMenuNodeDto covertMenuNode(UmsMenu menu, List<UmsMenu> menuList, Boolean withResourceYn) {
        UmsMenuNodeDto node = new UmsMenuNodeDto();
        BeanUtils.copyProperties(menu, node);
        List<UmsMenuNodeDto> children = menuList.stream()
                .filter(subMenu -> subMenu.getParentId().equals(menu.getId()))
                .map(subMenu -> covertMenuNode(subMenu, menuList, withResourceYn)).collect(Collectors.toList());
        node.setChildren(children);
        if (withResourceYn) {
            UmsResourceExample umsResourceExample = new UmsResourceExample();
            umsResourceExample.createCriteria().andMenuIdEqualTo(node.getId());
            List<UmsResource> umsResources = resourceMapper.selectByExample(umsResourceExample);
            List<UmsResourceDto> umsResourceDtos = BeanUtil.copyToList(umsResources, UmsResourceDto.class);
            umsResourceDtos.stream().forEach(e->e.setTitle(e.getName()));
            node.setResourceList(umsResourceDtos);
        }
        return node;
    }
}
